package spring.boot.client.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import spring.boot.client.common.NettyClientConstant;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class NettyClient {

    @Autowired
    private NettyClientHandlerInitializer nettyClientHandlerInitializer;

    /**
     * 启动 Netty Client
     */
    @PostConstruct
    public void start() throws InterruptedException {
        //创建 Bootstrap 对象，用于 Netty Client 启动
        Bootstrap bootstrap = new Bootstrap();
        // 设置 Bootstrap 的各种属性。
        bootstrap.group(NettyClientConstant.CLIENT_EVENT_GROUP) // 设置一个 EventLoopGroup 对象
                .channel(NioSocketChannel.class)  // 指定 Channel 为客户端 NioSocketChannel
                .remoteAddress(NettyClientConstant.SERVER_HOST, NettyClientConstant.SERVER_PORT) // 指定链接服务器的地址
                .option(ChannelOption.SO_KEEPALIVE, true) // TCP Keepalive 机制，实现 TCP 层级的心跳保活功能
                .option(ChannelOption.TCP_NODELAY, true) // 允许较小的数据包的发送，降低延迟
                .handler(nettyClientHandlerInitializer);
        // 链接服务器，并异步等待成功，即启动客户端
        bootstrap.connect().addListener((ChannelFutureListener) future -> {
            // 连接失败
            if (!future.isSuccess()) {
                log.error("Netty客户端启动,连接服务器[{}:{}]失败", NettyClientConstant.SERVER_HOST, NettyClientConstant.SERVER_PORT);
                reconnect();
                return;
            }
            // 连接成功
            NettyClientConstant.CLIENT_CHANNEL = future.channel();
            log.info("Netty客户端启动,连接服务器[{}:{}]成功", NettyClientConstant.SERVER_HOST, NettyClientConstant.SERVER_PORT);
        });
    }

    public void reconnect() {
        NettyClientConstant.CLIENT_EVENT_GROUP.schedule(() -> {
            log.info("Netty客户端开始重连......");
            try {
                start();
                NettyClientConstant.HEART_START_NUM = 0L;
            } catch (InterruptedException e) {
                log.error("Netty客户端重连失败,msg=[{}]", e.getMessage(), e);
            }
        }, NettyClientConstant.CLIENT_RECONNECT_SECONDS, TimeUnit.SECONDS);
        log.info("Netty客户端[{}]秒后将发起重连", NettyClientConstant.CLIENT_RECONNECT_SECONDS);
    }

    /**
     * 关闭 Netty
     * 优雅关闭一个 EventLoopGroup 对象
     */
    @PreDestroy
    public void shutdown() {
        if (NettyClientConstant.CLIENT_CHANNEL != null) {
            NettyClientConstant.CLIENT_CHANNEL.close();
        }
        NettyClientConstant.CLIENT_EVENT_GROUP.shutdownGracefully();
    }

}
